package com.rickpan.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.rickpan.dto.response.TeamMessageDTO;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 消息重试和死信处理服务
 * 负责失败消息的重试机制和死信队列处理
 * 
 * @author 开发团队协调员
 * @since 2025-07-17
 */
@Service
@ConditionalOnProperty(name = "spring.rabbitmq.host", matchIfMissing = false)
public class MessageRetryService {

    private static final Logger logger = LoggerFactory.getLogger(MessageRetryService.class);

    @Autowired
    private TeamMessageProducer teamMessageProducer;

    // 重试配置
    private static final int MAX_RETRY_COUNT = 3;
    private static final long INITIAL_RETRY_DELAY = 1000; // 1秒
    private static final double RETRY_MULTIPLIER = 2.0; // 指数退避

    // 重试任务调度器
    private final ScheduledExecutorService retryScheduler = Executors.newScheduledThreadPool(5);
    
    // 重试统计
    private final Map<String, AtomicInteger> retryStatsMap = new ConcurrentHashMap<>();
    
    // 死信消息记录
    private final Map<String, DeadLetterRecord> deadLetterMap = new ConcurrentHashMap<>();

    // ==================== 消息重试机制 ====================

    /**
     * 处理消息发送失败，启动重试机制
     * 
     * @param message 失败的消息
     * @param exception 失败原因
     */
    public void handleMessageFailure(TeamMessageDTO message, Exception exception) {
        String messageKey = generateMessageKey(message);
        int currentRetryCount = message.getRetryCount() != null ? message.getRetryCount() : 0;
        
        logger.warn("⚠️ 消息发送失败，准备重试: teamId={}, messageId={}, retryCount={}, error={}", 
                   message.getTeamId(), message.getId(), currentRetryCount, exception.getMessage());

        if (currentRetryCount < MAX_RETRY_COUNT) {
            // 启动重试
            scheduleRetry(message, currentRetryCount + 1, exception);
        } else {
            // 重试次数超限，发送到死信队列
            handleDeadLetter(message, exception);
        }
        
        // 更新重试统计
        updateRetryStats(messageKey, currentRetryCount >= MAX_RETRY_COUNT);
    }

    /**
     * 调度消息重试
     * 
     * @param message 消息
     * @param retryCount 重试次数
     * @param lastException 上次失败的异常
     */
    private void scheduleRetry(TeamMessageDTO message, int retryCount, Exception lastException) {
        // 计算重试延迟（指数退避）
        long delay = (long) (INITIAL_RETRY_DELAY * Math.pow(RETRY_MULTIPLIER, retryCount - 1));
        
        logger.info("🔄 调度消息重试: teamId={}, messageId={}, retryCount={}, delay={}ms", 
                   message.getTeamId(), message.getId(), retryCount, delay);

        retryScheduler.schedule(() -> {
            try {
                // 更新重试次数
                message.setRetryCount(retryCount);
                
                // 重新发送消息
                teamMessageProducer.retryTeamMessage(message, retryCount);
                
                logger.info("✅ 消息重试成功: teamId={}, messageId={}, retryCount={}", 
                           message.getTeamId(), message.getId(), retryCount);
                
            } catch (Exception e) {
                logger.error("❌ 消息重试失败: teamId={}, messageId={}, retryCount={}", 
                            message.getTeamId(), message.getId(), retryCount, e);
                
                // 递归处理重试失败
                handleMessageFailure(message, e);
            }
        }, delay, TimeUnit.MILLISECONDS);
    }

    // ==================== 死信队列处理 ====================

    /**
     * 处理死信消息
     * 
     * @param message 死信消息
     * @param lastException 最后一次失败的异常
     */
    private void handleDeadLetter(TeamMessageDTO message, Exception lastException) {
        String messageKey = generateMessageKey(message);
        
        logger.error("💀 消息进入死信队列: teamId={}, messageId={}, finalError={}", 
                    message.getTeamId(), message.getId(), lastException.getMessage());

        // 创建死信记录
        DeadLetterRecord record = new DeadLetterRecord(
            message, 
            lastException, 
            System.currentTimeMillis(),
            MAX_RETRY_COUNT
        );
        
        deadLetterMap.put(messageKey, record);
        
        // 发送死信通知（可选）
        sendDeadLetterNotification(record);
        
        // 记录死信统计
        updateDeadLetterStats(message.getMessageType());
    }

    /**
     * 发送死信通知
     * 
     * @param record 死信记录
     */
    @Async
    private void sendDeadLetterNotification(DeadLetterRecord record) {
        try {
            // 这里可以实现死信通知逻辑
            // 例如：发送邮件、推送告警、记录到监控系统等
            
            logger.warn("📧 死信通知: teamId={}, messageId={}, error={}", 
                       record.getMessage().getTeamId(), 
                       record.getMessage().getId(), 
                       record.getLastException().getMessage());
            
        } catch (Exception e) {
            logger.error("❌ 死信通知发送失败", e);
        }
    }

    /**
     * 手动重新处理死信消息
     * 
     * @param messageKey 消息键
     * @return 是否成功
     */
    public boolean reprocessDeadLetter(String messageKey) {
        DeadLetterRecord record = deadLetterMap.get(messageKey);
        if (record == null) {
            logger.warn("⚠️ 死信消息不存在: messageKey={}", messageKey);
            return false;
        }

        try {
            TeamMessageDTO message = record.getMessage();
            
            // 重置重试次数
            message.setRetryCount(0);
            
            // 重新发送消息
            teamMessageProducer.sendTeamMessage(message);
            
            // 从死信队列中移除
            deadLetterMap.remove(messageKey);
            
            logger.info("✅ 死信消息重新处理成功: messageKey={}", messageKey);
            return true;
            
        } catch (Exception e) {
            logger.error("❌ 死信消息重新处理失败: messageKey={}", messageKey, e);
            return false;
        }
    }

    /**
     * 获取所有死信消息
     * 
     * @return 死信消息列表
     */
    public Map<String, DeadLetterRecord> getAllDeadLetters() {
        return new ConcurrentHashMap<>(deadLetterMap);
    }

    /**
     * 清理过期的死信记录
     * 
     * @param maxAgeHours 最大保留时间（小时）
     */
    public void cleanupExpiredDeadLetters(int maxAgeHours) {
        long maxAge = maxAgeHours * 3600000L; // 转换为毫秒
        long currentTime = System.currentTimeMillis();
        
        int removedCount = 0;
        for (Map.Entry<String, DeadLetterRecord> entry : deadLetterMap.entrySet()) {
            if (currentTime - entry.getValue().getTimestamp() > maxAge) {
                deadLetterMap.remove(entry.getKey());
                removedCount++;
            }
        }
        
        if (removedCount > 0) {
            logger.info("🧹 清理过期死信记录: 清理数量={}, 剩余数量={}", removedCount, deadLetterMap.size());
        }
    }

    // ==================== 统计和监控 ====================

    /**
     * 更新重试统计
     * 
     * @param messageKey 消息键
     * @param isDeadLetter 是否进入死信队列
     */
    private void updateRetryStats(String messageKey, boolean isDeadLetter) {
        String key = isDeadLetter ? "dead_letter_count" : "retry_count";
        retryStatsMap.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet();
    }

    /**
     * 更新死信统计
     * 
     * @param messageType 消息类型
     */
    private void updateDeadLetterStats(String messageType) {
        String key = "dead_letter_" + messageType;
        retryStatsMap.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet();
    }

    /**
     * 获取重试统计信息
     * 
     * @return 统计信息
     */
    public Map<String, Integer> getRetryStats() {
        Map<String, Integer> stats = new ConcurrentHashMap<>();
        retryStatsMap.forEach((key, value) -> stats.put(key, value.get()));
        return stats;
    }

    /**
     * 重置统计信息
     */
    public void resetStats() {
        retryStatsMap.clear();
        logger.info("📊 重试统计已重置");
    }

    // ==================== 工具方法 ====================

    /**
     * 生成消息键
     * 
     * @param message 消息
     * @return 消息键
     */
    private String generateMessageKey(TeamMessageDTO message) {
        return String.format("team_%d_msg_%d", message.getTeamId(), message.getId());
    }

    /**
     * 关闭重试调度器
     */
    public void shutdown() {
        retryScheduler.shutdown();
        try {
            if (!retryScheduler.awaitTermination(10, TimeUnit.SECONDS)) {
                retryScheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            retryScheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }
        logger.info("🔒 消息重试服务已关闭");
    }

    // ==================== 内部类 ====================

    /**
     * 死信记录
     */
    public static class DeadLetterRecord {
        private final TeamMessageDTO message;
        private final Exception lastException;
        private final long timestamp;
        private final int maxRetryCount;

        public DeadLetterRecord(TeamMessageDTO message, Exception lastException, 
                              long timestamp, int maxRetryCount) {
            this.message = message;
            this.lastException = lastException;
            this.timestamp = timestamp;
            this.maxRetryCount = maxRetryCount;
        }

        // Getters
        public TeamMessageDTO getMessage() { return message; }
        public Exception getLastException() { return lastException; }
        public long getTimestamp() { return timestamp; }
        public int getMaxRetryCount() { return maxRetryCount; }
    }
}
